package haxe.util.unit;

import haxe.util.Collection;
import haxe.util.Stack;

class TestCollection extends haxe.unit.TestCase
{
	private var c:Collection<Dynamic>;
	
	public function tearDown() : Void
	{
		this.c.clear();
	}
	
	private function addRandom( ?col:Collection<Dynamic> ):Int
	{
		if ( col == null )
			col = this.c;
		var rand:Int = Math.round( Math.random()*100 );
		for ( i in 0...rand )
		{
			this.c.add( Math.random() );
		}
		return rand;
	}
	
	public function testClear():Void
	{
		this.c.clear();
		this.assertEquals( 0, this.c.size );
		this.assertTrue( this.c.isEmpty() );
	}
	
	public function testAdd():Void
	{
		var size = this.c.size;
		var rand:Int = this.addRandom();
		this.assertEquals( size+rand, this.c.size );
	}
	
	public function testAddAll():Void
	{
		var size = this.c.size;
		var tmp:Stack<Int> = new Stack<Int>();
		var rand:Int = addRandom( tmp );
		this.c.addAll( tmp );
		this.assertEquals( size + rand , this.c.size );
	}
	
	public function testAddRemove():Void
	{
		this.c.clear();
		var rand:Int = addRandom();
		var count:Int = 0;
		var size = this.c.size;
		for ( i in this.c )
		{
			if ( this.c.remove( i ) )
				++count;
		}
		this.assertEquals( size - count, this.c.size );
	}
	
	public function testContains():Void
	{
		var rand:Int = this.addRandom();
		var a:Array<Dynamic> = this.c.toArray();
		for ( i in a )
		{
			this.assertTrue( c.contains( i ) );
		}
			
		for ( i in rand...rand+20 )
			this.assertFalse( c.contains( i ) );
	}
	
	public function testContainsWithEqualsFunction():Void
	{
		var rand:Int = this.addRandom();
		var a:Array<Dynamic> = this.c.toArray();
		var eq:Dynamic->Dynamic->Bool = function( a:Dynamic, b:Dynamic )
		{
			return ( a - b ) == 0 ;
		}
		for ( i in a )
		{
			this.assertTrue( c.contains( i, eq ) );
		}
			
		for ( i in rand...rand+20 )
			this.assertFalse( c.contains( i, eq ) );
	}
	
	public function testContainsAllWithEqualsFunction():Void
	{
		this.c.clear();
		this.addRandom();
		var tmp:Stack<Int> = new Stack<Int>(); 
		this.addRandom( tmp );
		var eq:Dynamic->Dynamic->Bool = function( a:Dynamic, b:Dynamic )
		{
			return ( a - b ) == 0 ;
		}
		this.assertTrue( c.containsAll( tmp, eq ) );
	}
	
	public function testIsEmpty():Void
	{
		this.c.clear();
		this.assertTrue( this.c.isEmpty() );
		this.c.add( 0 );
		this.assertFalse( this.c.isEmpty() );
		this.c.clear();
		this.assertTrue( this.c.isEmpty() );
	}
	
	public function testIterate():Void
	{
		this.c.clear();
		var rand = this.addRandom();
		var size:Int = this.c.size;
		var count:Int = 0;
		for ( i in this.c )
		{
			++count;
		}
		this.assertEquals( rand, count );
		this.assertEquals( this.c.size, count );
	}
	
	public function testRemove():Void
	{
		this.c.clear();
		this.c.add( "test" );
		this.assertTrue( this.c.remove( "test" ) );
		this.assertTrue( this.c.isEmpty() );
	}
	
	public function testRemoveAll():Void
	{
		var tmp:Stack<Dynamic> = new Stack<Dynamic>();
		var rand:Int = addRandom();
		var size:Int = this.c.size;
		this.c.add( "test1" );tmp.add( "test1" );
		this.c.add( "test2" );tmp.add( "test2" );
		this.c.add( "test3" );tmp.add( "test3" );
		this.c.add( "test4" );tmp.add( "test4" );
		this.assertTrue( this.c.removeAll( tmp ) );
		this.assertEquals( size , this.c.size );
	}
	
	public function testToArray():Void
	{
		this.c.clear();
		var rand = this.addRandom();
		var a:Array<Dynamic> = c.toArray();
		this.assertEquals( a.length, this.c.size );
		for ( i in a )
			this.assertTrue( this.c.contains( i ) );
	}
}